#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Predesys Server - Error Log - Log Server
@version: 0.2.5
@license: GPL 3.0 (see "license" file)
@author: Jose A. Jimenez
@contact: jajimc@gmail.com"""

import sys
sys.dont_write_bytecode = True
import os
import cPickle
import logging
import logging.handlers
import SocketServer
import struct
import daemon

LOGFILE_PATH = "/var/log/predesys-server.log"

# Log file maximum size in bytes
LOGFILE_MAXSIZE = 10485760

# File to save process ID
DAEMON_PID_FILE = "/tmp/predesys-server-logserver.pid"

class LogRecordStreamHandler(SocketServer.StreamRequestHandler):
    """Handler for a streaming logging request.
    This basically logs the record using whatever logging policy is configured locally."""

    def handle(self):
        """Handle multiple requests - each expected to be a 4-byte length, followed by the LogRecord in pickle format.
        Logs the record according to whatever policy is configured locally."""
        while 1:
            chunk = self.connection.recv(4)
            if len(chunk) < 4: break
            slen = struct.unpack(">L", chunk)[0]
            chunk = self.connection.recv(slen)
            
            while len(chunk) < slen:
                chunk = chunk + self.connection.recv(slen - len(chunk))
            
            obj = self.unPickle(chunk)
            record = logging.makeLogRecord(obj)
            self.handleLogRecord(record)

    def unPickle(self, data):
        return cPickle.loads(data)

    def handleLogRecord(self, record):
        # If a name is specified, we use the named logger rather than the one implied by the record.
        if self.server.logname is not None:
            name = self.server.logname
        else:
            name = record.name
            
        logger = logging.getLogger(name)
        logger.handle(record)

class LogRecordSocketReceiver(SocketServer.ThreadingTCPServer):
    allow_reuse_address = 1

    def __init__(self, host="localhost", port=logging.handlers.DEFAULT_TCP_LOGGING_PORT, handler=LogRecordStreamHandler):
        SocketServer.ThreadingTCPServer.__init__(self, (host, port), handler)
        self.abort = 0
        self.timeout = 1
        self.logname = None

    def check_logfile_size(self):
        if os.path.isfile(LOGFILE_PATH) and os.path.getsize(LOGFILE_PATH) > LOGFILE_MAXSIZE:
            with open(LOGFILE_PATH, "w") as f:
                pass
            
    def serve_until_stopped(self):
        import select
        abort = 0
        
        while not abort:
            rd, wr, ex = select.select([self.socket.fileno()], [], [], self.timeout)
            if rd:
                self.check_logfile_size()
                self.handle_request()
            abort = self.abort

class LogServerDaemon(daemon.Daemon):
    """Predesys Server Log Server daemon. It does all the work of the daemon."""
    def __init__(self):
        daemon.Daemon.__init__(self, pidfile=DAEMON_PID_FILE)
              
    def run(self):
        """Does the daemon work."""
        try:
            logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", filename=LOGFILE_PATH)
            tcpServer = LogRecordSocketReceiver()
            tcpServer.serve_until_stopped()
        except:
            pass
        
if __name__ == "__main__":
    if len(sys.argv) == 2:
        if sys.argv[1] == "start":
            LogServerDaemon().start()
        elif sys.argv[1] == "restart":
            LogServerDaemon().restart()
        elif sys.argv[1] == "stop":
            LogServerDaemon().stop()
        else:
            print "Unknown command"
            sys.exit(2)
        sys.exit(0)
    else:
        print "Usage: %s start|stop|restart" % sys.argv[0]
        sys.exit(2)
